home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / atpar20.arc / ATPARITY.ASM next >
Assembly Source File  |  1985-12-11  |  21KB  |  518 lines

  1. PAGE 80,132
  2. PAGE
  3. TITLE  ATPARITY.COM  - PC/AT PARITY INTERCEPTOR  V2.0
  4. SUBTTL (C) John R. Petrocelli  12/11/85
  5. ;          3890 Carman Rd.
  6. ;          Schenectady, N.Y. 12303
  7. PAGE
  8. ;
  9. ;
  10. ; ATPARITY.COM  DETECTS PARITY ERRORS, LOGS THEM TO THE SCREEN AND
  11. ;               PRINTER, IF AVAILABLE, BEEPS, AND RETURNS TO PROGRAM
  12. ;               EXECUTION. SYSTEM DOES NOT HALT WHEN THIS PROGRAM IS
  13. ;               RESIDENT. PARITY ERROR CHECKING IS TERMINATED AFTER
  14. ;               FIRST ERROR IS DETECTED. THE ERROR MESSAGE INCLUDES
  15. ;               THE TIME OF THE EVENT.
  16. ;
  17. ;               There is a chance that, if the parity error occurrs in
  18. ;               a critical program or data, your system will still lock up.
  19. ;               With the default IBM BIOS Handler you will always hang
  20. ;               and have to reach for the Big Red Switch Interupt!
  21. ;
  22. ;
  23. ;               This Parity Error Handler emulates the standard PC/AT
  24. ;               Parity Error Handler reporting parity errors to the nearest
  25. ;               64k block. Perhaps if an error is occurring just beyond
  26. ;               the resident utilities the offending bank of 128k chips
  27. ;               could be swaped with the first bank of 128k chips.
  28. ;               NOTE --- 128k chips which are actually two 64k chips
  29. ;                        piggybacked are NOT completely pin compatable
  30. ;                        with 64k chips.
  31. ;
  32. ; VER 2.0 DIFFERENCES
  33. ;
  34. ;              Version 1.0 did not report the failing address. This
  35. ;              version (2.0) will report the filing 64k block of
  36. ;              memory if at all possible.
  37. ;
  38. ;
  39. ; DISCLAMER    The author makes no waranties with regard to the use of
  40. ;              this program and assumes no responsibility for lost data.
  41. ;              One may use this program at his own risk. It has been
  42. ;              tested as far as possible and performs as specified.
  43. ;
  44. ;              This program may be freely copied and distributed for non
  45. ;              commercial use and NO CHARGE is to be associated with such
  46. ;              copying and distribution.
  47. ;
  48. ;              Any suggestions, comments or problems should be fowarded
  49. ;              to the author.
  50. ;
  51. ;********************** EQUATES **************************************
  52.  
  53. BASE_RAM          EQU    10H
  54. MFG_PORT          EQU    80H
  55. PORT_A            EQU    60H
  56. PORT_B            EQU    61H
  57. PARITY_ERR        EQU    0C0H
  58. READ_8042_INPUT   EQU    0C0H
  59. CMOS_PORT         EQU    070H
  60. RAM_PAR_OFF       EQU    00001100B
  61. RAM_PAR_ON        EQU    11110011B
  62. PRTY_CHK          EQU    10000000B
  63. IO_CHK            EQU    01000000B
  64. STATUS_PORT       EQU    64H
  65. OUT_BUF_FULL      EQU    01H
  66. INPT_BUF_FULL     EQU    02H
  67. DIS_KBD           EQU    0ADH
  68. ENA_KBD           EQU    0AEH
  69. FF                EQU    0CH              ;FORM FEED
  70. CR                EQU    0DH              ;CARRAGE RETURN
  71. LF                EQU    0AH              ;LINE FEED
  72. BEEP              EQU    07H              ;BEEP
  73. EOM               EQU    '$'              ;END OF MESSAGE
  74. ASCII_0           EQU    '0'              ;ASCII CHARACTER 0
  75. ASCII_1           EQU    '1'              ;ASCII CHARACTER 1
  76. ASCII_2           EQU    '2'              ;ASCII CHARACTER 2
  77. PRINTER_ACK_OK    EQU    00101001B        ;PRINTER ACKNOWLEGE OK
  78. AT_ID             EQU    0FCH             ;AT ID AT  FFFF:000E
  79.                                           ;XT   IS 0FEH
  80.                                           ;PC   IS 0FFH
  81.                                           ;PCjr IS 0FDH
  82.  
  83. ;********************** ADDRESS OF ROM ID ****************************
  84.  
  85. ROM    SEGMENT AT 0FFFFH
  86.        ORG     0EH
  87. ROM_ID         DB ?
  88. ROM    ENDS
  89.  
  90. ;********************** ADDRESS OF INTERRUPT VECTORS *****************
  91.  
  92. VECTS  SEGMENT AT 0H
  93.        ORG     2H*4
  94. INT_2          DW ?
  95. VECTS  ENDS
  96.  
  97. ;********************** ADDRESS OF BIOS DATA SEGMENT *****************
  98.  
  99. DATA   SEGMENT AT 40H
  100.        ORG     13H
  101. MEMORY_SIZE    DW  ?
  102.        ORG      6CH
  103. TIMER_LOW       DW     ?
  104. TIMER_HIGH      DW     ?
  105. DATA   ENDS
  106.  
  107. ;********************** BEGINNING OF ATPARITY INSTRUCTIONS ***********
  108.  
  109. CSEG   SEGMENT
  110.        ASSUME  CS:CSEG               ;CS POINTS TO CODE SEGMENT
  111.        ORG     100H                  ;NEEDED FOR .COM
  112.  
  113. START: JMP    NMI_NEW
  114.  
  115.  
  116. ;********************** NMI HANDLER **********************************
  117.  
  118. NEW_NMI PROC   NEAR                  ;START OF NEW NMI HANDLER
  119.  
  120.         ASSUME DS:DATA               ;DS TO POINT TO BIOS DATA AREA IN RAM
  121.  
  122.         CLI                          ;BE SURE THAT INTERUPTS ARE OFF
  123.                                      ;THEY ARE OFF NORMALLY AT THE
  124.                                      ;START OF ANY INTERUPT ROUTINE
  125.  
  126.         JMP    GO                    ;JUMP OVER PROGRAM DATA
  127.  
  128. ;---------------------- PROGRAM DATA AREA -----------------------------
  129. ;
  130. ;      LOADED AND COPY_R MESSAGES ARE IN RESIDENT PORTION OF CODE
  131. ;      SO THAT THEY WILL APPEAR IF THE RESIDENT PROGRAMS ARE SCANNED
  132. ;      FOR IN RAM
  133. ;----------------------------------------------------------------------
  134.  
  135. LOADED   DB  "PC/AT PARITY ERROR INTERCEPTOR  V2.0  INSTALLED",CR,LF,EOM
  136. COPY_R   DB  "(C) John R. Petrocelli, Schenectady,N.Y.  12/11/85",CR,LF,EOM
  137. PAR1     DB    FF,BEEP,CR,LF,"PARITY ERROR "
  138. PAR1X    DB    0,BEEP,CR,LF
  139. PAR_SEG  DB    5 DUP("?")," (S)    (20 BIT ADDR.  4 HIGHEST ARE SIGNIFICANT)",CR,LF
  140. TIME     DB    "TIME: ??:??",0DH,0AH
  141. PAROFF   DB    "PARITY CHECKING WILL BE DISABLED !",CR,LF,BEEP,FF
  142. MSG_LEN  DW    $-OFFSET PAR1
  143.  
  144. MFG_SAV  DB    ?            ;MFG_PORT SAVE
  145. CMS_SAV  DB    ?            ;CMOS_PORT SAVE
  146. STA_SAV  DB    ?            ;STATUS_PORT SAVE
  147. PTB_SAV  DB    ?            ;PORT_B SAVE
  148.  
  149.  
  150. ;---------------------- TEMPORARY PROGRAM STACK ----------------------
  151. STACK    DW    50 DUP(?)           ;STACK IS 25 WORDS DEEP !
  152. STACK_HI DW    $-2                 ;POINTER TO END OF STACK
  153.  
  154. OLD_SS   DW    ?                   ;SAVE FOR STACK SEG ON ENTRY
  155. OLD_SP   DW    ?                   ;SAVE FOR STACK PTR ON ENTRY
  156.  
  157. ;---------------------- MAIN PROGRAM ---------------------------------
  158.  
  159.  
  160. GO:     MOV    CS:OLD_SS,SS          ;SAVE OLD STACK SEGMENT
  161.         MOV    CS:OLD_SP,SP          ;AND STACK POINTER
  162.         MOV    SP,CS                 ;POINT TO OUR INTERNAL STACK SEG
  163.         MOV    SS,SP
  164.         MOV    SP,CS:STACK_HI        ;AND STACK POINTER
  165.  
  166.         PUSH   AX                    ;PUSH ALL GENERAL REGISTERS
  167.         PUSH   BX                    ;INTO OUR STACK
  168.         PUSH   CX
  169.         PUSH   DX
  170.         PUSH   SI
  171.         PUSH   DI
  172.         PUSH   DS
  173.         PUSH   ES
  174.  
  175.         IN     AL,MFG_PORT           ;GET NMI COUNT
  176.         INC    AL                    ;INCREMENT NMI COUNT BY 1
  177.         JMP    SHORT $+2             ;I/O DELAY
  178.         OUT    MFG_PORT,AL           ;SAVE NMI COUNT
  179.  
  180.         MOV    CS:MFG_SAV,AL         ;SAVE MFG_PORT STATUS
  181.  
  182.         IN     AL,PORT_B             ;GET VALUE IN PORT_B
  183.         TEST   AL,PARITY_ERR         ;IS IT A PARITY ERROR ?
  184.         MOV    AH,AL                 ;SAVE STATUS
  185.         JNZ    NMI_1                 ;YES - CONTINUE
  186.         JMP    D14                   ;NO  - EXIT
  187.  
  188. NMI_1:
  189.         MOV    CS:PTB_SAV,AH         ;SAVE PORT_B STATUS
  190.  
  191.         MOV    AL,DIS_KBD            ;DISABLE KEYBOARD
  192.         CALL   C8042
  193.         IN     AL,PORT_A             ;FLUSH
  194.         MOV    AL,READ_8042_INPUT    ;GET THE SWITCH SETTINGS
  195.         CALL   C8042
  196.         CALL   OBF_42                ;WAIT FOR OUTPUT BUFFER FULL
  197.         IN     AL,PORT_A             ;GET THE SWITCH
  198.         OUT    MFG_PORT,AL           ;SAVE THE SWITCH
  199.  
  200.         MOV    DX,DATA               ;MAKE DS POINT TO BIOS DATA IN RAM
  201.         MOV    DS,DX
  202.         MOV    CS:PAR1X,ASCII_1      ;PUT ASCII 1 IN MESSAGE
  203.         TEST   AH,40H                ;I/O PARITY
  204.         JNZ    NMI_2                 ;YES - CONTINUE
  205.         MOV    CS:PAR1X,ASCII_2      ;PUT ASCII 2 IN MESSAGE
  206.                                      ;MUST BE PLANAR
  207. NMI_2:
  208.         IN     AL,CMOS_PORT          ;GET CURRENT VALUE OF CMOS_PORT
  209.         MOV    CS:CMS_SAV,AL         ;SAVE CMOS_PORT VALUE
  210.         JMP    SHORT $+2             ;I/O DELAY
  211.  
  212.         IN     AL,STATUS_PORT        ;GET CURRENT VALUE OF STATUS_PORT
  213.         MOV    CS:STA_SAV,AL         ;SAVE STATUS_PORT VALUE
  214.  
  215.         MOV    AL,0FFH               ;MASK TRAP
  216.         OUT    CMOS_PORT,AL
  217.         IN     AL,PORT_B
  218.         JMP    SHORT $+2             ;I/O DELAY
  219.  
  220.         OR     AL,RAM_PAR_OFF        ;TURN OFF NMI FLAG
  221.         OUT    PORT_B,AL             ;TURN OFF NMI
  222.         JMP    SHORT $+2             ;I/O DELAY
  223.         AND    AL,RAM_PAR_ON         ;TURN ON NMI FLAG
  224.         OUT    PORT_B,AL             ;TURN ON NMI
  225.  
  226.         MOV    BX,MEMORY_SIZE        ;GET # OF 1K BLOCKS OF MEMORY INSTALLED
  227.         CLD                          ;SET DIRECTION TO INCREMENT
  228.         SUB    DX,DX                 ;MAKE DX = 0
  229.  
  230. NMI_LOOP:
  231.         MOV    DS,DX                 ;DS AND ES TO POINT TO
  232.         MOV    ES,DX                 ;STARTING SEGMENT FOR SCAN
  233.         MOV    CX,4000H*2            ;4000h*2 for 64k scan
  234.  
  235.         SUB    SI,SI                 ;SI = 0   START OF SCAN
  236.  
  237.         REP    LODSW                 ;READ MEMORY 1 WORD AT A TIME CX TIMES
  238.                                      ;TO REPRODUCE PARITY ERROR IF POSSIBLE
  239.  
  240.         IN     AL,PORT_B             ;GET PARITY CHECK STATUS
  241.         XCHG   AL,AH                 ;SAVE STATUS
  242.         CMP    DX,4000H              ;END OF FIRST 256k ?
  243.         JB     NMI_3                 ;NO - JMP TO TEST RAM PARITY CHECK
  244.  
  245.         CMP    DX,8000H              ;ABOVE 512k ?
  246.         JAE    NMI_4                 ;NO - JMP TO TEST I/O PARITY CHECK
  247.  
  248.         IN     AL,MFG_PORT           ;GET SWITCH SETTINGS
  249.         TEST   AL,BASE_RAM           ;CHECK FOR 2ND 256K OF BASE RAM
  250.         JZ     NMI_4                 ;NO - JMP TO TEST I/O PARITY CHECK
  251.  
  252. NMI_3:  TEST   AH,PRTY_CHK           ;CHECK FOR RAM PARITY CHECK
  253.         JMP    NMI_5                 ;JMP OVER I/O PARITY TEST
  254.  
  255. NMI_4:  TEST   AH,IO_CHK             ;CHECK FOR I/O PARITY CHECK
  256. NMI_5:  JNZ    PRT_NMI               ;GO PRINT IF ERROR HAPPENED
  257.  
  258.         ADD    DX,1000H              ;1000h for 64k scan
  259.  
  260.         SUB    BX,64D                ;64d for 64k scan
  261.  
  262.         JNZ    NMI_LOOP              ;IF BX NOT 0 THEN CONTINUE SINCE
  263.                                      ;WE HAVE NOT FINISHED SCAN AND NO
  264.                                      ;PARITY ERROR HAPPENED
  265.  
  266.         JMP    PR_NMX                ;ELSE PRINT WITHOUT ADDRESS
  267.                                      ;????? IS SEGMENT
  268.  
  269. PRT_NMI:
  270.         MOV    DX,DS                 ;DS HAS SEGMENT WHERE ERROR HAPPENED
  271.         LEA    BX,PAR_SEG            ;BX HAS OFFSET IN SEGMENT OF MESSAGE
  272.  
  273.         MOV    AH,0                  ;SET AH = 0
  274.         MOV    AL,DH                 ;SET AL FOR CALL
  275.         CALL   ASCII_CONVERT         ;CALL TO CONVERT AL TO 2 BYTE ASCII
  276.                                      ;AND STORE IN MESSAGE AREA
  277.  
  278.         MOV    AH,0                  ;SET AH = 0
  279.         MOV    AL,DL                 ;SET AL FOR CALL
  280.         ADD    BX,2                  ;BX ADVANCED TO NEXT 2 BYTES OF MESSAGE
  281.         CALL   ASCII_CONVERT         ;CALL TO CONVERT AL TO 2 BYTE ASCII
  282.                                      ;AND STORE IN MESSAGE AREA
  283.  
  284.         ADD    BX,2                  ;BX ADVANCED TO NEXT 2 BYTES OF MESSAGE
  285.         MOV    BYTE PTR CS:[BX],ASCII_0  ;PUT ASCII 0 AT END OF SEGMENT IN
  286.                                          ;MESSAGE
  287.  
  288. PR_NMX:
  289.         CALL   GET_TIME              ;GET TIME FROM BIOS DATA AREA IN RAM
  290.                                      ;AND PUT IN MESSAGE AREA
  291.  
  292.         XOR    DX,DX                 ;SET DX TO FIRST PRINTER
  293.         MOV    AH,2                  ;SET AH TO GET PRINTER STATUS
  294.         INT    17H                   ;CALL BIOS TO GET PRINTER STATUS
  295.         TEST   AH,PRINTER_ACK_OK     ;TEST FOR PRINTER RESPONSE
  296.         JNZ    DISPL                 ;NO RESPONSE THEN JUST DISPLAY
  297.  
  298.         MOV    SI,OFFSET PAR1        ;SI POINTS TO START OF MESSAGE
  299.         MOV    CX,CS:MSG_LEN         ;CX IS NUMBER OF CHARACTERS TO PRINT
  300. PR_LOOP:
  301.         MOV    AL,CS:[SI]            ;CHARACTER TO PRINT IN AL
  302.         INC    SI                    ;ADVANCE TO NEXT CHAR
  303.         MOV    AH,0                  ;FUNCTION TO PRINT CHARACTER IN AL
  304.         MOV    DX,0                  ;DX IS PRINTER TO USE
  305.         INT    17H                   ;CALL BIOS TO PRINT CHARACTER
  306.         LOOP   PR_LOOP               ;LOOP FOR CX CHARACTERS
  307. DISPL:
  308.         MOV    SI,OFFSET PAR1        ;SI POINTS TO START OF MESSAGE
  309.         INC    SI                    ;FORM FEED NOT NEEDED SO SKIP
  310.                                      ;FIRST CHARACTER
  311.  
  312.         MOV    CX,CS:MSG_LEN         ;CX IS NUMBER OF CHARACTERS TO PRINT
  313.         SUB    CX,2                  ;FORM FEED NOT NEEDED SO REDUCE
  314.                                      ;NUMBER OF CHARACTERS TO PRINT BY 2
  315.  
  316. DI_LOOP:
  317.         MOV    AL,CS:[SI]            ;CHARACTER TO PRINT IN AL
  318.         INC    SI                    ;ADVANCE TO NEXT CHAR
  319.         MOV    AH,14                 ;FUNCTION TO DISPLAY CHARACTER IN AL
  320.         MOV    BH,0                  ;FOREGROUND COLOR TO USE
  321.         INT    10H                   ;CALL BIOS TO DISPLAY CHARACTER IN AL
  322.         LOOP   DI_LOOP               ;LOOP FOR CX CHARACTERS
  323.  
  324.         JMP    SHORT $+2             ;I/O DELAY
  325.  
  326.         MOV    AL,PTB_SAV            ;GET SAVED VALUE OF PORT_B
  327.  
  328.         OR     AL,RAM_PAR_OFF        ;TURN OFF NMI FLAG
  329.         OUT    PORT_B,AL             ;TURN OFF NMI
  330.         JMP    SHORT $+2             ;I/O DELAY
  331.  
  332.         MOV    AL,ENA_KBD            ;LOAD COMND TO ENABLE KEYBOARD
  333.         OUT    STATUS_PORT,AL        ;AND ENABLE THE KEYBOARD
  334.         JMP    SHORT $+2             ;I/O DELAY
  335.  
  336.         MOV    AL,CS:CMS_SAV         ;GET SAVED CMOS_PORT VALUE
  337.         OUT    CMOS_PORT,AL          ;RESTORE CMOS_PORT VALUE
  338.         JMP    SHORT $+2             ;I/O DELAY
  339.  
  340.         MOV    AL,CS:STA_SAV         ;GET SAVED STATUS_PORT VALUE
  341.         OUT    STATUS_PORT,AL        ;RESTORE STATUS_PORT VALUE
  342.         JMP    SHORT $+2             ;I/O DELAY
  343.  
  344.         MOV    AL,CS:MFG_SAV         ;GET SAVED MFG_PORT VALUE
  345.         OUT    MFG_PORT,AL           ;RESTORE MFG_PORT VALUE
  346.         JMP    SHORT $+2             ;I/O DELAY
  347.  
  348.         JMP    EXIT                  ;JMP TO EXIT
  349.  
  350. D14:
  351.         MOV    AL,8FH                ;SET AL TO MASK OFF PARITY CHECKING
  352.         OUT    CMOS_PORT,AL          ;DISABLE PARITY CHECKING
  353.         JMP    SHORT $+2             ;I/O DELAY
  354.         MOV    AL,0FH                ;SET AL TO MASK ON PARITY CHECKING
  355.         OUT    CMOS_PORT,AL          ;ENABLE PARITY CHECKING
  356.         JMP    SHORT $+2             ;I/O DELAY
  357.  
  358. EXIT:
  359.         POP    ES                    ;RESTORE ALL REGISTERS
  360.         POP    DS
  361.         POP    DI
  362.         POP    SI
  363.         POP    DX
  364.         POP    CX
  365.         POP    BX
  366.         POP    AX
  367.  
  368.         MOV    SS,CS:OLD_SS          ;RESTORE SAVED STACK SEGMENT
  369.         MOV    SP,CS:OLD_SP          ;AND POINTER
  370.  
  371.         IRET                         ;RETURN FROM INTERUPT ROUTINE
  372.  
  373. NEW_NMI ENDP                         ;END OF NMI HANDLER MAIN ROUTINE
  374.  
  375.  
  376. ;********************** SUBROUTINES **********************************
  377.  
  378. C8042:                               ;ISSUE COMMAND TO THE 8042
  379.         CLI                          ;INTERUPTS SHOULD ALREADY BE OFF
  380.         OUT    STATUS_PORT,AL        ;SEND VALUE IN AL TO STATUS_PORT
  381.  
  382.         SUB    CX,CX
  383. C42_1:  IN     AL,STATUS_PORT
  384.         TEST   AL,INPT_BUF_FULL
  385.         LOOPNZ C42_1
  386.         RET                          ;RETURN TO CALLER
  387.  
  388.  
  389. OBF_42:                              ;WAIT FOR 8042 RESPONSE
  390.         SUB    CX,CX
  391.         MOV    BL,6
  392. C42_2:  IN     AL,STATUS_PORT
  393.         TEST   AL,OUT_BUF_FULL
  394.         JNZ    C42_3
  395.         LOOP   C42_2
  396.         DEC    BL
  397.         JNZ    C42_2
  398. C42_3:  RET                          ;RETURN TO CALLER
  399.  
  400. ASCII_CONVERT:                       ;CONVERT A BYTE IN AL TO ITS
  401.                                      ;2 BYTE ASCII EQUIVALENT AND STORE
  402.                                      ;IN MESSAGE AREA POINTED TO BY BX
  403.  
  404.         PUSH   AX                    ;SAVE AX
  405.         MOV    CL,4
  406.         SHR    AL,CL
  407.         CALL   CALC                  ;CALCULATE
  408.         MOV    BYTE PTR CS:[BX],AL   ;STORE FIRST ASCII BYTE IN BX
  409.  
  410.         POP    AX                    ;RESTORE AX
  411.         AND    AL,0FH
  412.         CALL   CALC                  ;CALCULATE
  413.         MOV    BYTE PTR CS:[BX+1],AL ;STORE SECOND ASCII BYTE IN BX+1
  414.         RET                          ;RETURN TO CALLER
  415.  
  416. CALC:                                ;CALCULATE ASCII EQUIVALENT
  417.         ADD    AL,090H
  418.         DAA
  419.         ADC    AL,040H
  420.         DAA
  421.         RET                          ;RETURN TO CALLER
  422.  
  423. GET_TIME:                            ;GET THE HOURS AND MINUTES FROM
  424.                                      ;BIOS DATA AREA IN RAM
  425.  
  426.         PUSH   AX                    ;SAVE REGISTERS
  427.         PUSH   BX
  428.         PUSH   CX
  429.         PUSH   DX
  430.         PUSH   DS
  431.  
  432.         MOV    DX,DATA               ;DS TO POINT FO BIOS DATA AREA IN
  433.         MOV    DS,DX                 ;RAM
  434.  
  435.         MOV    AX,TIMER_HIGH         ;GET HIGH PORTION OF TIMER COUNT
  436. CHECK:
  437.         CMP    AX,24                 ;IS IT GREATER THAN 24
  438.         JLE    GOOD_TIME             ;NO - OK CONTINUE
  439.         SUB    AX,24                 ;YES - SUBTRACT 24 AND
  440.         JMP    CHECK                 ;CHECK AGAIN
  441. GOOD_TIME:
  442.         AAM                          ;CHANGE TO HOURS TO ASCII
  443.         ADD    AX,3030H
  444.         LEA    BX,TIME               ;BX POINTS TO FIRST PART OF TIME
  445.                                      ;IN MESSAGE AREA
  446.         MOV    CS:[BX+6],AH          ;HOURS - HIGH     INTO MESSAGE AREA
  447.         MOV    CS:[BX+7],AL          ;HOURS - LOW      INTO MESSAGE AREA
  448.  
  449.         MOV    AX,TIMER_LOW          ;GET LOW PORTION OF TIMER COUNT
  450.         MOV    CX,8                  ;ISOLATE MINUTES AND CONVERT TO ASCII
  451.         SHR    AX,CL
  452.         MOV    DX,60
  453.         MUL    DL
  454.         SHR    AX,CL
  455.         AAM
  456.         ADD    AX,3030H
  457.         MOV    CS:[BX+9],AH          ;MINUTES - HIGH   INTO MESSAGE AREA
  458.         MOV    CS:[BX+10],AL         ;MINUTES - LOW    INTO MESSAGE AREA
  459.  
  460.         POP    DS                    ;RESTORE ALL SAVED REGISTERS
  461.         POP    DX
  462.         POP    CX
  463.         POP    BX
  464.         POP    AX
  465.         RET                          ;RETURN TO CALLER
  466.  
  467. ;********************** INSTALL NMI HANDLER **************************
  468.  
  469. NMI_NEW PROC   NEAR                  ;INSTALL NEW NMI HANDLER
  470.         JMP    CHECK_AT              ;JMP OVER DATA
  471.  
  472. NO_LOAD DB  "PC/AT PARITY ERROR INTERCEPTOR  V2.0  >NOT< INSTALLED !",CR,LF,BEEP,EOM
  473. NOT_AT  DB  "SYSTEM IS NOT A PC/AT !",CR,LF,EOM
  474.  
  475. CHECK_AT:
  476.         ASSUME DS:ROM                ;POINT DS TO ROM
  477.         MOV    AX,ROM                ;
  478.         MOV    DS,AX                 ;
  479.         MOV    AL,ROM_ID             ;GET MACHINE ID
  480.         PUSH   CS                    ;PUSH CS AND
  481.         POP    DS                    ;RESTORE DS
  482.  
  483.         CMP    AL,AT_ID              ;IS MACHINE A PC/AT
  484.         JZ     INSTALL               ;YES - INSTALL NEW NMI HANDLER
  485.                                      ;NO  - PRINT ERROR MESSAGE AND EXIT
  486.         MOV    DX,OFFSET NO_LOAD     ;DX IS ADDR OF MESSAGE TO PRINT
  487.         MOV    AH,9                  ;DOS FUNCTION TO PRINT
  488.         INT    21H                   ;CALL DOS
  489.         MOV    DX,OFFSET COPY_R      ;DX IS ADDR OF MESSAGE TO PRINT
  490.         MOV    AH,9                  ;DOS FUNCTION TO PRINT
  491.         INT    21H                   ;CALL DOS
  492.         MOV    DX,OFFSET NOT_AT      ;DX IS ADDR OF MESSAGE TO PRINT
  493.         MOV    AH,9                  ;DOS FUNCTION TO PRINT
  494.         INT    21H                   ;CALL DOS
  495.         INT    20H                   ;TERMINATE WITHOUT INSTALLING
  496.  
  497. INSTALL:                             ;INSTALL NEW NMI HANDLER
  498.         MOV    DX,OFFSET LOADED      ;DX IS ADDR OF MESSAGE TO PRINT
  499.         MOV    AH,9                  ;DOS FUNCTION TO PRINT
  500.         INT    21H                   ;CALL DOS
  501.         MOV    DX,OFFSET COPY_R      ;DX IS ADDR OF MESSAGE TO PRINT
  502.         MOV    AH,9                  ;DOS FUNCTION TO PRINT
  503.         INT    21H                   ;CALL DOS
  504.  
  505.         ASSUME DS:VECTS              ;DS POINTS TO INTERUPT VECTORS
  506.         PUSH   DS
  507.         MOV    AX,VECTS
  508.         MOV    DS,AX
  509.         MOV    INT_2,OFFSET NEW_NMI  ;REPLACE STANDARD NMI HANDLER
  510.         MOV    INT_2[2],CS           ;WITH NEW NMI HANDLER
  511.         MOV    DX,OFFSET NMI_NEW     ;DX POINTS TO END OF RESIDENT CODE+1
  512.         INT    27H                   ;TERMINATE AND STAY RESIDENT
  513. NMI_NEW ENDP
  514. CSEG    ENDS
  515.         END    START                 ;END OF PROGRAM
  516. ;-----------------------------------------------------------------------
  517. ;-----------------------------------------------------------------------
  518.